package com.myBlog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.myBlog.constants.SystemConstants;
import com.myBlog.domain.ResponseResult;
import com.myBlog.domain.dto.MenuDTO;
import com.myBlog.domain.entity.Menu;
import com.myBlog.domain.entity.RoleMenu;
import com.myBlog.domain.entity.UserRole;
import com.myBlog.domain.vo.MenuTreeVo;
import com.myBlog.domain.vo.MenuVo;
import com.myBlog.domain.vo.RoleMenuTreeSelectVo;
import com.myBlog.mapper.MenuMapper;
import com.myBlog.mapper.RoleMenuMapper;
import com.myBlog.mapper.UserRoleMapper;
import com.myBlog.service.MenuService;
import com.myBlog.service.RoleMenuService;
import com.myBlog.service.RoleService;
import com.myBlog.service.UserRoleService;
import com.myBlog.utils.BeanCopyUtils;
import com.myBlog.utils.SecurityUtils;
import com.myBlog.utils.SystemConverter;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.myBlog.enums.AppHttpCodeEnum.*;

/**
 * 菜单权限表(Menu)表服务实现类
 *
 * @author makejava
 * @since 2023-03-19 10:10:41
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
    @Resource
    private RoleMenuService roleMenuService;
    @Resource
    private UserRoleService userRoleService;

    @Override
    public List<String> selectPermsUserId(Long id) {
        //如果是管理员，返回所有的权限
        if (SecurityUtils.isAdmin()) {
            LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(Menu::getMenuType, SystemConstants.CATEGORY, SystemConstants.BUTTON);
            wrapper.eq(Menu::getStatus, SystemConstants.STATUS_NORMAL);
            List<Menu> menus = list(wrapper);
            List<String> perms = menus.stream()
                    .map(Menu::getPerms)
                    .collect(Collectors.toList());
            return perms;
        }
        //否则，返回所具有的权限
        return getBaseMapper().selectPermsByUserId(id);
    }

    @Override
    public List<Menu> selectRouterMenuTreeByUserId(Long userId) {
        MenuMapper menuMapper = getBaseMapper();
        List<Menu> menus = null;
        //判断是否为管理员
        if (SecurityUtils.isAdmin()) {
            //是，返回所有符合要求的Menu
            menus = menuMapper.selectAllRouterMenu();
        } else {
            //不是，返回当前用户所具有的Menu
            menus = menuMapper.selectRouterMenuTreeByUserId(userId);
        }
        //构建tree
        List<Menu> menuTree = buildMenuTree(menus, 0L);
        return menuTree;
    }

    /**
     * 菜单列表
     *
     * @param menuName
     * @param status
     * @return
     */
    @Override
    public ResponseResult list(String menuName, String status) {
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.hasText(menuName), Menu::getMenuName, menuName);
        wrapper.eq(StringUtils.hasText(status), Menu::getStatus, status);
        wrapper.orderByAsc(Menu::getOrderNum);
        wrapper.orderByAsc(Menu::getParentId);
        List<Menu> menus = list(wrapper);
        List<MenuVo> menuVos = BeanCopyUtils.copyBeanList(menus, MenuVo.class);

        return ResponseResult.okResult(menuVos);
    }

    /**
     * 添加菜单
     *
     * @param menuDTO
     * @return
     */
    @Override
    @Transactional
    public ResponseResult addMenu(MenuDTO menuDTO) {

        Menu menu = BeanCopyUtils.copyBean(menuDTO, Menu.class);
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Menu::getMenuName, menu.getMenuName());
        Menu oneMenu = getOne(queryWrapper);
        if (!Objects.isNull(oneMenu)) {
            return ResponseResult.errorResult(ADD_MENU_FAIL);
        }

        save(menu);

        Long userId = SecurityUtils.getUserId();
        LambdaQueryWrapper<UserRole> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserRole::getUserId, userId);
        UserRole userRole = userRoleService.getOne(wrapper);
        Long roleId = userRole.getRoleId();
        RoleMenu roleMenu = new RoleMenu(roleId, menu.getId());
        roleMenuService.save(roleMenu);

        return ResponseResult.okResult();
    }

    /**
     * 根据id查询菜单信息
     *
     * @param menuId
     * @return
     */
    @Override
    public ResponseResult getMenuInfo(Long menuId) {
        Menu menu = getById(menuId);

        MenuVo menuVo = BeanCopyUtils.copyBean(menu, MenuVo.class);

        return ResponseResult.okResult(menuVo);
    }

    /**
     * 查询菜单列表
     *
     * @param menu
     * @return
     */
    @Override
    public List<Menu> selectMenuList(Menu menu) {

        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        //menuName模糊查询
        queryWrapper.like(StringUtils.hasText(menu.getMenuName()), Menu::getMenuName, menu.getMenuName());
        queryWrapper.eq(StringUtils.hasText(menu.getStatus()), Menu::getStatus, menu.getStatus());
        //排序 parent_id和order_num
        queryWrapper.orderByAsc(Menu::getParentId, Menu::getOrderNum);
        List<Menu> menus = list(queryWrapper);
        ;
        return menus;
    }

    /**
     * 新增角色
     *
     * @return
     */
    @Override
    public ResponseResult getMenuTree() {

        List<Menu> menus = selectMenuList(new Menu());
        List<MenuTreeVo> menuTreeVos = SystemConverter.buildMenuSelectTree(menus);
        return ResponseResult.okResult(menuTreeVos);
    }

    /**
     * 修改菜单
     *
     * @param menuDTO
     * @return
     */
    @Override
    public ResponseResult updateMenu(MenuDTO menuDTO) {
        if (!StringUtils.hasText(menuDTO.getMenuName()) ||
                !StringUtils.hasText(menuDTO.getMenuType()) ||
                !StringUtils.hasText(String.valueOf(menuDTO.getStatus())) ||
                !StringUtils.hasText(menuDTO.getPath()) ||
                !StringUtils.hasText(String.valueOf(menuDTO.getOrderNum())) ||
                !StringUtils.hasText(menuDTO.getIcon())) {
            return ResponseResult.errorResult(CONTENT_IS_BLANK);
        }
        Menu menu = BeanCopyUtils.copyBean(menuDTO, Menu.class);
        updateById(menu);
        return ResponseResult.okResult();
    }

    /**
     * 根据id删除菜单
     *
     * @param menuId
     * @return
     */
    @Override
    public ResponseResult deleteMenu(Long menuId) {
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Menu::getParentId, menuId);
        List<Menu> menus = list(wrapper);
        if (menus.size() != 0 && !Objects.isNull(menus)) {
            return ResponseResult.errorResult(DELETE_MENU_REFUSE);
        }

        removeById(menuId);
        return ResponseResult.okResult();
    }

    /**
     * 根据id查询权限菜单
     *
     * @param roleId
     * @return
     */
    @Override
    public ResponseResult roleMenuTreeSelect(Long roleId) {
        List<Menu> menus = selectMenuList(new Menu());
        List<Long> checkedKeys = this.selectMenuListByRoleId(roleId);
        List<MenuTreeVo> menuTreeVos = SystemConverter.buildMenuSelectTree(menus);
        RoleMenuTreeSelectVo roleMenuTreeSelectVo = new RoleMenuTreeSelectVo(checkedKeys, menuTreeVos);

        return ResponseResult.okResult(roleMenuTreeSelectVo);
    }

    /**
     * 选择菜单通过角色id列表
     *
     * @param roleId 角色id
     * @return {@link List}<{@link Long}>
     */
    public List<Long> selectMenuListByRoleId(Long roleId) {
        return getBaseMapper().selectMenuListByRoleId(roleId);
    }

    private List<Menu> buildMenuTree(List<Menu> menus, Long parentId) {
        List<Menu> menuTree = menus.stream()
                .filter(menu -> menu.getParentId().equals(parentId))
                .peek(menu -> menu.setChildren(getChildren(menu, menus)))
                .collect(Collectors.toList());
        return menuTree;
    }

    /**
     * 获取传入参数的子menu
     *
     * @param menu
     * @return
     */
    private List<Menu> getChildren(Menu menu, List<Menu> menus) {
        List<Menu> childrenList = menus.stream()
                .filter(m -> m.getParentId().equals(menu.getId()))
                .peek(menu1 -> menu1.setChildren(getChildren(menu1, menus)))
                .collect(Collectors.toList());
        return childrenList;
    }
}

